// 1.创建一个RefImpl对象 包装value值,对这个value的访问都是对这个对象的访问

import {isTracking, trackEffect, triggerEffct} from "./effect";
import {hasChanged, isObject} from "../shared";
import {reactive} from "./reactive";

export function trackRefValue(ref) {
    if (isTracking()) {
        trackEffect(ref.dep)
    }
}

class RefImpl {
    private _value: any;
    public dep;
    private _rawValue: any;
    private __v_isRef = true;

    constructor(value) {
        //  如果是个对象就用reactive包裹一下，如果不是就直接赋值
        this._rawValue = value;
        this._value = convert(value);
        this.dep = new Set();
    }

    get value() {
        trackRefValue(this);
        return this._value
    }

    set value(newValue) {
        if (hasChanged(this._rawValue, newValue)) {
            this._value = convert(newValue);
            this._rawValue = newValue
            triggerEffct(this.dep);
        }
    }
}

export function convert(value) {
    return isObject(value) ? reactive(value) : value;
}

export function ref(value) {
    return new RefImpl(value);
}

export function isRef(ref) {
    return !!ref.__v_isRef;
}

export function unRef(ref) {
    return isRef(ref) ? ref.value : ref;
}

export function proxyRefs(objectWithRef) {
    //  如果objectWithRef中key对应的值是ref类型的,
    //  那么就返回这个值的.value,否则就直接返回这个值.
    return new Proxy(objectWithRef, {
        get(target: any, p: string | symbol, receiver: any): any {
            return unRef(Reflect.get(target, p, receiver));
        },
        set(target: any, key: string | symbol, newValue: any, receiver: any): boolean {
            if (isRef(target[key]) && !isRef(newValue)) {
                return target[key].value = newValue;
            } else {
                return Reflect.set(target, key, newValue, receiver);
            }
        }
    })

}